package cn.lwj.webService.util;

import cn.lwj.webService.entity.DataJzbView;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Set;

public class NullFromXmlConverter implements Converter {
	
	 @SuppressWarnings("rawtypes")  
	    private Class currentType;   
	    private List<String> clazzNamesList = new ArrayList<String>();  
	  
	    @SuppressWarnings("rawtypes")  
	    @Override  
	    public boolean canConvert(Class type) {  
	        currentType = type;
            for (String key : DataJzbView.dataType.keySet()) {
                clazzNamesList.add(DataJzbView.dataType.get(key).getSimpleName());
            }
	        if (clazzNamesList.contains(currentType.getSimpleName())&&isBaseType(type)) {  
	            return true;  
	        } else {  
	            return false;  
	        }  
	    }  
	  
	    @Override  
	    public void marshal(Object source, HierarchicalStreamWriter writer,  
	            MarshallingContext context) {  
	        try {  
	            marshalSuper(source, writer, context, currentType);  
	        } catch (Exception e) {  
	            // TODO Auto-generated catch block  
	            e.printStackTrace();  
	  
	        }  
	    }  
	  
	    @SuppressWarnings({ "unchecked", "rawtypes" })  
	    private Object getObj(Class clazz, String nodeName, Object source)  
	            throws Exception { 
	    	Method method = null;
	    	if(nodeName.startsWith("dt")){
//	    		System.out.println("nodeName..."+nodeName);
	    		method = clazz.getMethod("get"  
		                + Character  
		                        .toUpperCase(nodeName.substring(0, 1).toCharArray()[0])  
		                + nodeName.substring(1)); 
	    	}
	    	else if(nodeName.startsWith("de")){
//	    		System.out.println("nodeName..."+nodeName);
	    		method = clazz.getMethod("get"  
		                + Character  
		                        .toUpperCase(nodeName.substring(0, 1).toCharArray()[0])  
		                + nodeName.substring(1)); 
	    	}
	    	else{
	    		method = clazz.getMethod("get"  
		                + Character  
		                        .toLowerCase(nodeName.substring(0, 1).toCharArray()[0])  
		                + nodeName.substring(1)); 
	    	}

	        Object obj = null;  
	        obj = method.invoke(clazz.cast(source), new Object[0]);  
	        return obj;  
	    }  
	  
	    @SuppressWarnings({ "rawtypes" })  
	    private void objConverter(Object source, HierarchicalStreamWriter writer,  
	            MarshallingContext context, Class clazz, String nodeName,  
	            Class fieldClazz) throws Exception {  
	        Object obj = getObj(clazz, nodeName, source);  
	        writer.startNode(nodeName); 
	        if(obj==null)
	        writer.addAttribute("xsi:nil", "true");
	        marshalSuper(obj, writer, context, fieldClazz);  
	        writer.endNode();  
	    }  
	  
	    @SuppressWarnings({ "rawtypes" })  
	    private void collectionConverter(Object source,  
	            HierarchicalStreamWriter writer, MarshallingContext context,  
	            Class clazz, String nodeName, Field field) throws Exception {  
	        Type types[] = ((ParameterizedType) field.getGenericType())  
	                .getActualTypeArguments();  
	        Object obj = getObj(clazz, nodeName, source);  
	        Collection collection = null;  
	        if (field.getType().equals(List.class)) {  
	            collection = (List) obj;  
	        } else if (field.getType().equals(Set.class)) {  
	            collection = (Set) obj;  
	        }  
	        writer.startNode(nodeName);  
	        for (Object object : collection) {  
	            String clazzName = ((Class) types[0]).getSimpleName();  
	            writer.startNode(Character.toLowerCase(clazzName.substring(0, 1)  
	                    .toCharArray()[0]) + clazzName.substring(1));  
	            marshalSuper(object, writer, context, (Class) types[0]);  
	            writer.endNode();  
	        }  
	        writer.endNode();  
	    }  
	  
	    @SuppressWarnings({ "rawtypes" })  
	    private void basicTypeConverter(Object source,  
	            HierarchicalStreamWriter writer, MarshallingContext context,  
	            Class clazz, String nodeName) throws Exception {  
	        Object obj = getObj(clazz, nodeName, source);  
	        writer.startNode(nodeName); 
	        if(obj==null){
	        	writer.addAttribute("xsi:nil", "true");
	        }else{
	        	writer.setValue(obj == null ? "" : obj.toString());  
	        }
	        writer.endNode();  
	    }  
	  
	    @SuppressWarnings({ "rawtypes" })  
	    private void marshalSuper(Object source, HierarchicalStreamWriter writer,  
	            MarshallingContext context, Class clazz) throws Exception {  
	        Field fields[] = clazz.getDeclaredFields();  
	        for (Field field : fields) {  
	            String nodeName = field.getName();  
	            Class fieldClazz = field.getType();  
	            if (clazzNamesList.contains(fieldClazz.getSimpleName())) {  
	                objConverter(source, writer, context, clazz, nodeName,  
	                        fieldClazz);  
	            } else if (Arrays.asList(fieldClazz.getInterfaces()).contains(  
	                    Collection.class)) {  
	                collectionConverter(source, writer, context, clazz, nodeName,  
	                        field);  
	            } else {  
	                basicTypeConverter(source, writer, context, clazz, nodeName);  
	            }  
	        }  
	    }  
	  
	    @Override  
	    public Object unmarshal(HierarchicalStreamReader reader,  
	            UnmarshallingContext context) {  
	    	if(reader.getAttribute("xsi:nil")!=null&&reader.getAttribute("xsi:nil").toString().equals("true")&&(reader.getValue()==null||reader.getValue().trim().equals(""))){
				return null;
			}else{
				return reader.getValue();
			}
	    }  
	  
	    /**
		 * 判断是否为基本类型
		 * @param type
		 * @return
		 * boolean
		 */
		private boolean isBaseType(Class<?> type) {
			if (type.equals(Integer.class) || type.equals(Double.class)
					|| type.equals(String.class) || type.equals(Boolean.class)
					|| type.equals(Long.class) || type.equals(Short.class)
					|| type.equals(Byte.class) || type.equals(Float.class)
					|| type.equals(BigDecimal.class) || type.equals(int.class)
					|| type.equals(float.class) || type.equals(long.class)
					|| type.equals(double.class) || type.equals(short.class)
					|| type.equals(boolean.class) || type.equals(byte.class)) {
				return true;
			}
			return false;
		}
		
		/**
		 * 判断是否为数字类型
		 * @param type
		 * @return
		 * boolean
		 */
		public boolean isNumValueType(Class<?> type) {
			if (type.equals(Integer.class) || type.equals(Double.class)
					|| type.equals(Long.class) || type.equals(Short.class)
					|| type.equals(Float.class) || type.equals(BigDecimal.class)
					|| type.equals(int.class) || type.equals(float.class)
					|| type.equals(long.class) || type.equals(double.class)
					|| type.equals(short.class)) {
				return true;
			}
			return false;
		}

}
